/*
 * MadHelix is a Java Swing-based GUI frontend for SoundHelix.
 * Copyright (C) 2017-2019, 2023 UltrasonicMadness
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 3 only,
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

package org.ultrasonicmadness.madhelix.dialogs;

import java.io.File;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Frame;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.Insets;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.JButton;
import javax.swing.JCheckBox;
import javax.swing.JDialog;
import javax.swing.JFileChooser;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JSpinner;
import javax.swing.JTextField;
import javax.swing.SpinnerNumberModel;

import org.ultrasonicmadness.madhelix.MadHelix;
import org.ultrasonicmadness.madhelix.concurrency.SoundHelixThread;
import org.ultrasonicmadness.madhelix.utils.PathUtils;

public class PrefsDialog extends JDialog {
    // Constants
    private final int MAX_TIMER_INTERVAL = 5000;
    private final String HISTORY_PATH = PathUtils.getHistoryPath();

    // The settings are stored in the SoundHelix thread if the OK button is
    // clicked.
    private SoundHelixThread soundHelix;

    // Used to clear history
    private MadHelix mainWindow;

    // Option components
    private JCheckBox fileExportCheckBox;
    private JCheckBox loggingSongsCheckBox;
    private JTextField fileLocationField = new JTextField();
    private JSpinner timerIntervalSpinner;

    public PrefsDialog(MadHelix mainWindow, SoundHelixThread soundHelix) {
        super(mainWindow, true);
        this.mainWindow = mainWindow;
        this.soundHelix = soundHelix;

        setUpPrefsDialog();
    }

    private void setUpPrefsDialog() {
        this.setTitle("MadHelix preferences");

        this.addWindowListener(new WindowListener() {
            @Override
            public void windowActivated(WindowEvent e) {}

            @Override
            public void windowClosed(WindowEvent e) {}

            @Override
            public void windowClosing(WindowEvent e) {
                try {
                    soundHelix.savePreferences();
                } catch (Exception x) {
                    System.out.println(x.getClass());

                    JOptionPane.showMessageDialog(PrefsDialog.this, x.getMessage().toString(),
                            "Exception occurred", JOptionPane.ERROR_MESSAGE);
                }
            }

            @Override
            public void windowDeactivated(WindowEvent e) {}

            @Override
            public void windowDeiconified(WindowEvent e) {}

            @Override
            public void windowIconified(WindowEvent e) {}

            @Override
            public void windowOpened(WindowEvent e) {}
        });

        JPanel prefsPanel = setUpPrefsPanel();
        JScrollPane prefsScrollPane = new JScrollPane(prefsPanel,
                JScrollPane.VERTICAL_SCROLLBAR_AS_NEEDED,
                JScrollPane.HORIZONTAL_SCROLLBAR_NEVER);

        this.add(prefsScrollPane);
        this.setMinimumSize(new Dimension(240, 120));
        this.pack();
        this.setLocationRelativeTo(null);
    }

    private JPanel setUpPrefsPanel() {
        JPanel prefsPanel = new JPanel();

        JPanel fileLocationPanel = setUpFileLocationPanel();
        JPanel timerIntervalPanel = setUpTimerIntervalPanel();
        JPanel historyPanel = setUpHistoryPanel();

        prefsPanel.setLayout(new GridBagLayout());

        GridBagConstraints constraints = new GridBagConstraints();
        constraints.insets = new Insets(4, 4, 4, 4);
        constraints.weightx = 1;
        constraints.anchor = GridBagConstraints.WEST;
        constraints.fill = GridBagConstraints.HORIZONTAL;
        constraints.gridy = 0;
        prefsPanel.add(fileLocationPanel, constraints);

        constraints.fill = GridBagConstraints.NONE;
        constraints.gridy = 1;
        prefsPanel.add(timerIntervalPanel, constraints);

        constraints.gridy = 2;
        prefsPanel.add(historyPanel, constraints);

        constraints.gridy = 3;
        constraints.weighty = 1;
        prefsPanel.add(new JPanel(), constraints);

        return prefsPanel;
    }

    private JPanel setUpFileLocationPanel() {
        JPanel fileLocationPanel = new JPanel();
        JLabel fileLocationLabel = new JLabel("MIDI output directory",
                JLabel.LEFT);
        JButton fileBrowseButton = new JButton("Browse...");
        JFileChooser fileChooser = new JFileChooser();

        boolean exportingMidi = soundHelix.isExportingMidi();
        boolean loggingSongs = soundHelix.isLoggingSongs();

        fileLocationField.addCaretListener(new CaretListener() {
            @Override
            public void caretUpdate(CaretEvent ev) {
                soundHelix.setMidiOutDir(new File(fileLocationField.getText()));
            }
        });

        fileExportCheckBox = new JCheckBox("Export MIDI files when playing",
                soundHelix.isExportingMidi());

        fileExportCheckBox.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ev) {
                boolean exportingMidi = fileExportCheckBox.isSelected();
                soundHelix.setExportingMidi(exportingMidi);

                fileLocationField.setEnabled(exportingMidi);
                fileBrowseButton.setEnabled(exportingMidi);
            }
        });

        fileChooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
        fileLocationField.setText(soundHelix.getMidiOutDir().toString());
        fileLocationField.setPreferredSize(new Dimension(0, 0));
        fileLocationField.setEnabled(exportingMidi);
        fileBrowseButton.setEnabled(exportingMidi);

        fileBrowseButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ev)
            {
                int fileStatus = fileChooser.showOpenDialog(PrefsDialog.this);

                // If 'Open' is clicked
                if (fileStatus == 0) {
                    fileLocationField.setText(fileChooser.getSelectedFile().toString());
                }
            }
        });

        fileLocationPanel.setLayout(new GridBagLayout());
        GridBagConstraints constraints = new GridBagConstraints();
        constraints.fill = GridBagConstraints.BOTH;
        constraints.anchor = GridBagConstraints.WEST;

        constraints.gridy = 0;
        constraints.gridwidth = 2;
        fileLocationPanel.add(fileExportCheckBox, constraints);

        constraints.gridy = 1;
        fileLocationPanel.add(fileLocationLabel, constraints);

        constraints.gridwidth = 1;
        constraints.gridy = 2;
        constraints.gridx = 0;
        constraints.weightx = 1;
        fileLocationPanel.add(fileLocationField, constraints);

        constraints.gridx = 1;
        constraints.weightx = 0;
        fileLocationPanel.add(fileBrowseButton, constraints);

        return fileLocationPanel;
    }

    private JPanel setUpTimerIntervalPanel() {
        JPanel timerIntervalPanel = new JPanel();
        JLabel timerIntervalLabel = new JLabel("Timer update interval");
        JLabel timerUnitLabel = new JLabel("ms");

        timerIntervalSpinner = new JSpinner(new SpinnerNumberModel(
                soundHelix.getTimerInterval(), 0, MAX_TIMER_INTERVAL, 1));

        timerIntervalSpinner.setToolTipText("If MadHelix lags when playing " +
                "songs, increase this value.");

        timerIntervalSpinner.addChangeListener(new ChangeListener() {
            @Override
            public void stateChanged(ChangeEvent ev) {
                soundHelix.setTimerInterval(
                        ((Integer)timerIntervalSpinner.getValue()).intValue());
            }
        });

        timerIntervalPanel.setLayout(new GridBagLayout());
        GridBagConstraints constraints = new GridBagConstraints();
        constraints.anchor = GridBagConstraints.WEST;
        constraints.insets = new Insets(0, 4, 0, 0);

        constraints.gridx = 0;
        timerIntervalPanel.add(timerIntervalLabel, constraints);

        constraints.gridx = 1;
        timerIntervalPanel.add(timerIntervalSpinner, constraints);

        constraints.gridx = 2;
        timerIntervalPanel.add(timerUnitLabel, constraints);

        return timerIntervalPanel;
    }

    private JPanel setUpHistoryPanel() {
        JPanel historyPanel = new JPanel();
        historyPanel.setLayout(new GridBagLayout());

        loggingSongsCheckBox = new JCheckBox("Log played songs to history",
                soundHelix.isLoggingSongs());

        loggingSongsCheckBox.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ev) {
                soundHelix.setLoggingSongs(loggingSongsCheckBox.isSelected());
            }
        });

        JButton clearHistoryButton = new JButton("Clear history");
        clearHistoryButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent ev) {
                File historyFile = new File(HISTORY_PATH);

                if (!historyFile.exists()) {
                    JOptionPane.showMessageDialog(PrefsDialog.this, "The log is already " +
                            "clear.", "MadHelix", JOptionPane.INFORMATION_MESSAGE);
                } else {
                    int userClearHistory = JOptionPane.showConfirmDialog(PrefsDialog.this,
                        "Are you sure you wish to clear your song history? " +
                        "This action cannot be reversed.",
                        "MadHelix",
                        JOptionPane.YES_NO_OPTION
                    );

                    if (userClearHistory == JOptionPane.YES_OPTION) {
                        if (historyFile.delete()) {
                            mainWindow.clearHistoryModel();
                        } else {
                            JOptionPane.showMessageDialog(PrefsDialog.this, "MadHelix could " +
                                "not delete history.xml.",
                                "I/O error",
                                JOptionPane.ERROR_MESSAGE
                            );
                        }
                    }
                }
            }
        });

        GridBagConstraints constraints = new GridBagConstraints();

        constraints.gridy = 0;
        constraints.insets = new Insets(0, 4, 0, 0);
        constraints.anchor = GridBagConstraints.WEST;
        historyPanel.add(loggingSongsCheckBox, constraints);
        constraints.gridy = 1;
        historyPanel.add(clearHistoryButton, constraints);

        return historyPanel;
    }
}
